package sk.stuba.fiit.clientApp.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.stereotype.Service;

import sk.stuba.fiit.clientApp.cvo.ArchiveCVO;
import sk.stuba.fiit.clientApp.cvo.ArchiveResultCVO;
import sk.stuba.fiit.clientApp.service.ArchiveService;
import sk.stuba.fiit.clientApp.singeltons.ApplicationContextSingelton;
import sk.stuba.fiit.clientApp.ws.client.ArchiveServiceClient;
import sk.stuba.fiit.ltasys.ws.schema.beans.ActionType;
import sk.stuba.fiit.ltasys.ws.schema.beans.ArchiveRequest;
import sk.stuba.fiit.ltasys.ws.schema.beans.ArchiveResponse;
import sk.stuba.fiit.ltasys.ws.schema.beans.DataType;
import sk.stuba.fiit.ltasys.ws.schema.beans.UserType;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


@Service("archiveService")
public class ArchiveServiceImpl implements ArchiveService{

	@Autowired
	private ArchiveServiceClient archiveServiceClient;
	
	private final static String  JAXB_BEAN = "marshaller-client";

	public static ApplicationContext singelton = ApplicationContextSingelton.getInstance();
	public static Jaxb2Marshaller controler =  (Jaxb2Marshaller) singelton.getBean(JAXB_BEAN);
	
	
	public ArchiveResultCVO archive(ArchiveCVO archiveCVO) throws Exception{
		ArchiveRequest request = new ArchiveRequest();
		
		File file = new File(archiveCVO.getFile());
		FileInputStream fis = new FileInputStream(file);
		byte [] data = new byte[(int) file.length()];
		fis.read(data);
		fis.close();
		BASE64Encoder encoder = new BASE64Encoder();
		DataType archivPackage = new DataType();
		archivPackage.withBinaryData(encoder.encode(data));
		
		UserType user = new UserType();
		user.setUserid(archiveCVO.getUserId());
		user.setUserName(archiveCVO.getUserName());
		user.setUserPassword(archiveCVO.getUserPassword());
		
		ActionType action = new ActionType();
		action.withArchive("I");
		
		request.setData(archivPackage );
		request.setUser(user );
		request.setAction(action);
		
		ArchiveResponse response = archiveServiceClient.processArchiveRequest(request );
		
		ArchiveResultCVO res = new ArchiveResultCVO();
		res.setStatusInfo(processArchiveResponseStatus(response.getStatus()));
		if(response.getData()!= null)
		res.setUserToken(response.getData().getToken());
		return res;
	}

	@Override
	public ArchiveResultCVO deleteArchivePackage(ArchiveCVO archiveCvo)
			throws Exception {
		ArchiveRequest request = new ArchiveRequest();
		UserType user = new UserType();
		user.setUserid(archiveCvo.getUserId());
		user.setUserName(archiveCvo.getUserName());
		user.setUserPassword(archiveCvo.getUserPassword());
		
		DataType archivPackage = new DataType();
		archivPackage.withToken(archiveCvo.getToken());
		
		ActionType action = new ActionType();
		action.withDelete("D");
		
		request.setData(archivPackage );
		request.setUser(user );
		request.setAction(action);
		ArchiveResponse response = archiveServiceClient.processArchiveRequest(request );
		
		ArchiveResultCVO res = new ArchiveResultCVO();
		res.setStatusInfo(processArchiveResponseStatus(response.getStatus()));
		return res;
	}


	@Override
	public ArchiveResultCVO obtainArchivePackage(ArchiveCVO archiveCvo)
			throws Exception {
		ArchiveRequest request = new ArchiveRequest();
		UserType user = new UserType();
		user.setUserid(archiveCvo.getUserId());
		user.setUserName(archiveCvo.getUserName());
		user.setUserPassword(archiveCvo.getUserPassword());
		
		DataType archivPackage = new DataType();
		archivPackage.withToken(archiveCvo.getToken());
		
		ActionType action = new ActionType();
		action.withGetting("G");
		
		request.setData(archivPackage);
		request.setUser(user );
		request.setAction(action);
		ArchiveResponse response = archiveServiceClient.processArchiveRequest(request );
		processResponse(response);
		ArchiveResultCVO res = new ArchiveResultCVO();
		res.setStatusInfo(processArchiveResponseStatus(response.getStatus()));
		if(response.getData()!= null)
		res.setUserToken(response.getData().getToken());
		return res;
	}
	
	private String processArchiveResponseStatus(int status) {
		switch(status){
		case 0: return "Operation was accepted by archive";
		case 1: return "Archiv operation fail";
		case 2: return "Incorect user name or user password";
		case 3: return "Incorect user tocen";
		case 4: return "Incorect data format for required operation";
		case 20: return "Data was delete from archive successfully";
		case 25: return "Some problem was ocured during delete operation";
		case 10: return "Data was archived successfully";
		case 15: return "Incorect data for archivation";
		}
		return "Unknow operation status";
	}

	public void processResponse(ArchiveResponse response) throws Exception{
		BASE64Decoder decoder = new BASE64Decoder();
		if(response.getData()!= null && response.getData().getBinaryData()!= null){
			
		
		byte [] binaryData = decoder.decodeBuffer(response.getData().getBinaryData());
		long time = System.currentTimeMillis();
		File tmpFile = new File(time+"tmp.zip");
		tmpFile.createNewFile();
		FileOutputStream fos = new FileOutputStream(tmpFile);
		fos.write(binaryData);
		fos.flush();
		fos.close();
		
		File archivFile = new File("ArchivePackage");
		if(archivFile.exists()){
			archivFile.delete();
		}
		archivFile.mkdir();
		
		ZipInputStream inStream = new ZipInputStream(new FileInputStream(tmpFile));
		ZipEntry entry;
        byte[] buffer = new byte[1024];
        int nrBytesRead; 
         
        while ((entry = inStream.getNextEntry()) != null) {
        	FileOutputStream fosUnzip = new FileOutputStream(archivFile.getAbsoluteFile()+File.separator+new File(entry.getName()));
              while ((nrBytesRead = inStream.read(buffer)) > 0) {
            	  fosUnzip.write(buffer, 0, nrBytesRead);
               }
            fosUnzip.close();
        }
        inStream.close();

        File evidenceRecord = new File(archivFile.getAbsoluteFile()+File.separator+"EvidenceRecord.xml");
        FileOutputStream fosEvidenceRec = new FileOutputStream(evidenceRecord);
        fosEvidenceRec.write(decoder.decodeBuffer(response.getArchivepackage()));
        fosEvidenceRec.close();
//    	Result result = new StreamResult(evidenceRecord); 
//    	controler.marshal(response.getArchivepackage(), result);
        tmpFile.delete();
		}
	}
}
